﻿namespace Comet.Presentation
{
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using EnvDTE;
    using Comet.Infrastructure;

    /// <summary>   
    ///     Interface for a data member view. 
    /// </summary>
    /// <remarks>   
    ///     Simon, 09.07.2010. 
    /// </remarks>
    public interface IDataMemberView
    {
        #region Data Members (4)

        DataMemberType DataMemberType
        {
            get;
            set;
        }

        /// <summary>   
        ///     Gets or sets a value indicating whether this object is selected. 
        /// </summary>
        /// <value> 
        ///     true if this object is selected, false if not. 
        /// </value>
        bool IsSelected
        {
            get;
            set;
        }

        /// <summary>   
        ///     Gets or sets the name. 
        /// </summary>
        /// <value> 
        ///     The name. 
        /// </value>
        string DataMemberName
        {
            get;
            set;
        }

        /// <summary>   
        ///     Gets or sets the name of the type. 
        /// </summary>
        /// <value> 
        ///     The name of the type. 
        /// </value>
        string TypeName
        {
            get;
            set;
        }

        /// <summary>   
        ///     Gets or sets the data member visibility. 
        /// </summary>
        /// <value> 
        ///     The data member visibility. 
        /// </value>
        DataMemberVisibility DataMemberVisibility
        {
            get;
            set;
        }
        #endregion Data Members

        #region Delegates and Events (2)

        // Events (2) 

        /// <summary> Event queue for all listeners interested in Deselected events. </summary>
        event EventHandler Deselected;

        /// <summary> Event queue for all listeners interested in Selected events. </summary>
        event EventHandler SelectionGained;

        #endregion Delegates and Events
    }

    /// <summary>   
    ///     Data members presenter. Represents capabilities of a 
    ///     data member's representation.
    /// </summary>
    /// <remarks>   
    ///     Simon, 09.07.2010. 
    /// </remarks>
    public class DataMemberPresenter
    {
        #region Fields (3)

        CodeElement dataMember;
        DataMemberType dataMemberType;
        bool isSelected;
        IDataMemberView view;
        DataMemberVisibility dataMemberVisibility;

        #endregion Fields

        #region Constructors (5)

        /// <summary>   
        ///     Creates a new instance of the DataMembersPresenter class. 
        /// </summary>
        /// <remarks>   
        ///     Simon, 09.07.2010. 
        /// </remarks>
        /// <param name="view">     The view. </param>
        /// <param name="variable"> The variable. </param>
        public DataMemberPresenter(IDataMemberView view, CodeVariable variable)
            : this(view)
        {
            this.dataMember = variable as CodeElement;
            this.dataMemberType = DataMemberType.Field;
            this.dataMemberVisibility = ToDataMemberVisibility(variable.Access);
            
            UpdateView();
        }

        /// <summary>   
        ///     Creates a new instance of the DataMembersPresenter class. 
        /// </summary>
        /// <remarks>   
        ///     Simon, 09.07.2010. 
        /// </remarks>
        /// <param name="view">     The view. </param>
        /// <param name="property"> The property. </param>
        public DataMemberPresenter(IDataMemberView view, CodeProperty property)
            : this(view)
        {
            this.dataMember = property as CodeElement;
            this.dataMemberType = DataMemberType.Property;
            this.dataMemberVisibility = ToDataMemberVisibility(property.Access);
        }

        /// <summary>   
        ///     Creates a new instance of the DataMembersPresenter class. 
        /// </summary>
        /// <remarks>   
        ///     Simon, 09.07.2010. 
        /// </remarks>
        /// <exception cref="ArgumentNullException">    Thrown when one or more required arguments are
        ///                                             null. </exception>
        /// <param name="view"> The view. </param>
        public DataMemberPresenter(IDataMemberView view)
        {
            if (view == null)
            {
                throw new ArgumentNullException("view");
            }

            this.View = view;
            RegisterEvents();
        }

        void RegisterEvents()
        {
            this.View.SelectionGained += this.View_Selected;
            this.View.Deselected += this.View_Deselected;
        }

        /// <summary>   
        ///     Creates a new instance of the DataMembersPresenter class. 
        /// </summary>
        /// <remarks>   
        ///     Simon, 10.07.2010. 
        /// </remarks>
        /// <param name="property"> The property. </param>
        public DataMemberPresenter(CodeProperty property)
        {
            this.dataMember = property as CodeElement;
            this.dataMemberType = DataMemberType.Property;
            this.dataMemberVisibility = ToDataMemberVisibility(property.Access);
        }

        /// <summary>   
        ///     Creates a new instance of the DataMembersPresenter class. 
        /// </summary>
        /// <remarks>   
        ///     Simon, 10.07.2010. 
        /// </remarks>
        /// <param name="field">    The field. </param>
        public DataMemberPresenter(CodeVariable field)
        {
            this.dataMember = field as CodeElement;
            this.dataMemberType = DataMemberType.Field;
            this.dataMemberVisibility = ToDataMemberVisibility(field.Access);
        }


        /// <summary>   
        ///     Creates a new instance of the DataMemberPresenter class. 
        /// </summary>
        /// <remarks>   
        ///     Simon, 10.07.2010. 
        /// </remarks>
        /// <exception cref="ArgumentException">    Thrown when dataMember is neither a CodeVariable nor
        ///                                         a CodeProperty. </exception>
        /// <param name="dataMember">   The data member. </param>
        public DataMemberPresenter(CodeElement dataMember)
        {
            if (dataMember is CodeVariable)
            {
                this.dataMemberType = DataMemberType.Field;
                this.dataMemberVisibility = ToDataMemberVisibility(((CodeVariable)dataMember).Access);
            }
            else if (dataMember is CodeProperty)
            {
                this.dataMemberType = DataMemberType.Property;
                this.dataMemberVisibility = ToDataMemberVisibility(((CodeProperty)dataMember).Access);
            }
            else
            {
                throw new ArgumentException("dataMember must be a CodeVariable or a CodeProperty");
            }

            this.dataMember = dataMember;
            
        }

        #endregion Constructors

        #region Properties (4)

        /// <summary>   
        ///     Gets the data member. 
        /// </summary>
        /// <value> 
        ///     The data member. 
        /// </value>
        public CodeElement DataMember
        {
            get { return dataMember; }
        }

        /// <summary>   
        ///     Gets the type of the data member. 
        /// </summary>
        /// <value> 
        ///     The type of the data member. 
        /// </value>
        public DataMemberType DataMemberType
        {
            get { return dataMemberType; }
        }

        /// <summary>   
        ///     Gets a value indicating whether this object is selected. 
        /// </summary>
        /// <value> 
        ///     true if this object is selected, false if not. 
        /// </value>
        public bool IsSelected
        {
            get
            {
                return isSelected;
            }
        }

        /// <summary>   
        ///     Gets or sets the view. 
        /// </summary>
        /// <value> 
        ///     The view. 
        /// </value>
        public IDataMemberView View
        {
            get { return (view); }
            set
            {
                if (view == value)
                {
                    return;
                }

                view = value;

                UpdateView();
                RegisterEvents();
            }
        }

        public DataMemberVisibility DataMemberVisibility
        {
            get { return (dataMemberVisibility); }
            set { dataMemberVisibility = value; }
        }



        #endregion Properties

        #region Methods (3)

        // Private Methods (3) 

        /// <summary>   
        ///     Updates the view assigned to this presenter. 
        /// </summary>
        /// <remarks>   
        ///     Simon, 09.07.2010. 
        /// </remarks>
        private void UpdateView()
        {
            if (this.View != null)
            {
                this.View.DataMemberName = this.dataMember.Name;
                
                if (this.dataMemberType == DataMemberType.Field)
                {
                    this.View.TypeName = ((CodeVariable)this.dataMember).Type.AsString;
                    
                }
                else if (this.dataMemberType == DataMemberType.Property)
                {
                    this.View.TypeName = ((CodeProperty)this.dataMember).Type.AsString;
                }

                this.View.DataMemberType = this.DataMemberType;
                this.View.DataMemberVisibility = this.DataMemberVisibility;
            }
        }

        /// <summary>   
        ///     Converts the vsCMAccess to a data member visibility. 
        /// </summary>
        /// <remarks>   
        ///     Simon, 10.07.2010. 
        /// </remarks>
        /// <exception cref="ArgumentException">    Thrown when one or more arguments have unsupported or
        ///                                         illegal values. </exception>
        /// <param name="vsCMAccess">   The access type. </param>
        /// <returns>   
        ///     This object as a Presentation.DataMemberVisibility. 
        /// </returns>
        private DataMemberVisibility ToDataMemberVisibility(vsCMAccess vsCMAccess)
        {
            return CometUtils.ToDataMemberVisibility(vsCMAccess);
        }


        /// <summary>   
        ///     Event handler. Called by View for deselected events. 
        /// </summary>
        /// <remarks>   
        ///     Simon, 09.07.2010. 
        /// </remarks>
        /// <param name="sender">   Source of the event. </param>
        /// <param name="e">        Event information. </param>
        void View_Deselected(object sender, EventArgs e)
        {
            this.isSelected = false;
        }

        /// <summary>   
        ///     Event handler. Called by View for selected events. 
        /// </summary>
        /// <remarks>   
        ///     Simon, 09.07.2010. 
        /// </remarks>
        /// <param name="sender">   Source of the event. </param>
        /// <param name="e">        Event information. </param>
        void View_Selected(object sender, EventArgs e)
        {
            this.isSelected = true;
        }

        #endregion Methods
    }
}